#include <cassert>
#include <gtkmm.h>
#include <list>
#include <iostream>
#include "colour.h"
#include "display.h"
#include "gradientchooser.h"

GradientChooser::GradientChooser(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& refGlade)
	: Gtk::Dialog(cobject) {
	refGlade->get_widget("button_insertbefore", button_insertbefore_);
	button_insertbefore_->signal_clicked().connect(sigc::mem_fun(*this, &GradientChooser::on_button_insertbefore_clicked));
	refGlade->get_widget("button_edit", button_edit_);
	button_edit_->signal_clicked().connect(sigc::mem_fun(*this, &GradientChooser::on_button_edit_clicked));
	refGlade->get_widget("button_insertafter", button_insertafter_);
	button_insertafter_->signal_clicked().connect(sigc::mem_fun(*this, &GradientChooser::on_button_insertafter_clicked));
	refGlade->get_widget("button_remove", button_remove_);
	button_remove_->signal_clicked().connect(sigc::mem_fun(*this, &GradientChooser::on_button_remove_clicked));
	refGlade->get_widget("treeview", treeview_);
	liststore_ = Gtk::ListStore::create(columns_);
	treeview_->set_model(liststore_);
	treeview_->append_column_numeric("r", columns_.red_, "%02X");
	treeview_->append_column_numeric("g", columns_.green_, "%02X");
	treeview_->append_column_numeric("b", columns_.blue_, "%02X");
}

void GradientChooser::setColours(std::list<Colour>* colours) {
	colours_ = colours;
	liststore_->clear();
	for (std::list<Colour>::iterator iter = colours->begin(); iter != colours->end(); ++iter) {
		Gtk::TreeModel::Row row = *(liststore_->append());
		row[columns_.iter_] = iter;
		row[columns_.red_] = iter->r;
		row[columns_.green_] = iter->g;
		row[columns_.blue_] = iter->b;
	}
}

void GradientChooser::setDisplay(Display* display) {
	display_ = display;
}

void GradientChooser::on_button_insertbefore_clicked() {
	assert(colours_ != NULL);
	assert(display_ != NULL);
	Gtk::ColorSelectionDialog colourSelection;
	if (colourSelection.run() != Gtk::RESPONSE_OK) {
		return;
	}
	Gdk::Color colour = colourSelection.get_color_selection()->get_current_color();
	std::list<Colour>::iterator iter;
	Gtk::TreeModel::Row row;
	Glib::RefPtr<Gtk::TreeSelection> selection = treeview_->get_selection();
	Gtk::TreeIter selected = selection->get_selected();
	if (selection->count_selected_rows() == 0) {
		colours_->push_front(Colour((uint8_t)(colour.get_red() >> 8), (uint8_t)(colour.get_green() >> 8), (uint8_t)(colour.get_blue() >> 8)));
		iter = colours_->begin();
		row = *(liststore_->prepend());
	} else {
		iter = colours_->insert((*selected)[columns_.iter_], Colour((uint8_t)(colour.get_red() >> 8), (uint8_t)(colour.get_green() >> 8), (uint8_t)(colour.get_blue() >> 8)));
		row = *(liststore_->insert(selected));
	}
	row[columns_.iter_] = iter;
	row[columns_.red_] = row.get_value(columns_.iter_)->r;
	row[columns_.green_] = row.get_value(columns_.iter_)->g;
	row[columns_.blue_] = row.get_value(columns_.iter_)->b;
	if (button_remove_->get_sensitive() == false) {
		button_remove_->set_sensitive(true);
	}
	display_->updateImage();
}

void GradientChooser::on_button_edit_clicked() {
	assert(colours_ != NULL);
	assert(display_ != NULL);
	Glib::RefPtr<Gtk::TreeSelection> selection = treeview_->get_selection();
	if (selection->count_selected_rows() == 0) {
		return;
	}
	Gtk::TreeModel::Row row = *(selection->get_selected());
	Gtk::ColorSelectionDialog colourSelection;
	Gdk::Color colour;
	colour.set_rgb((gushort)(row.get_value(columns_.red_) * 257), (gushort)(row.get_value(columns_.green_) * 257), (gushort)(row.get_value(columns_.blue_) * 257));
	colourSelection.get_colorsel()->set_current_color(colour);
	if (colourSelection.run() != Gtk::RESPONSE_OK) {
		return;
	}
	colour = colourSelection.get_color_selection()->get_current_color();
	row.get_value(columns_.iter_)->r = (uint8_t)(colour.get_red() >> 8);
	row.get_value(columns_.iter_)->g = (uint8_t)(colour.get_green() >> 8);
	row.get_value(columns_.iter_)->b = (uint8_t)(colour.get_blue() >> 8);
	row[columns_.red_] = row.get_value(columns_.iter_)->r;
	row[columns_.green_] = row.get_value(columns_.iter_)->g;
	row[columns_.blue_] = row.get_value(columns_.iter_)->b;
	display_->updateImage();
}

void GradientChooser::on_button_insertafter_clicked() {
	assert(colours_ != NULL);
	assert(display_ != NULL);
	Gtk::ColorSelectionDialog colourSelection;
	if (colourSelection.run() != Gtk::RESPONSE_OK) {
		return;
	}
	Gdk::Color colour = colourSelection.get_color_selection()->get_current_color();
	std::list<Colour>::iterator iter;
	Gtk::TreeModel::Row row;
	Glib::RefPtr<Gtk::TreeSelection> selection = treeview_->get_selection();
	Gtk::TreeIter selected = selection->get_selected();
	++selected;
	if (selection->count_selected_rows() == 0 || selected == liststore_->children().end()) {
		colours_->push_back(Colour((uint8_t)(colour.get_red() >> 8), (uint8_t)(colour.get_green() >> 8), (uint8_t)(colour.get_blue() >> 8)));
		iter = colours_->end();
		--iter;
		row = *(liststore_->append());
	} else {
		iter = colours_->insert((*selected)[columns_.iter_], Colour((uint8_t)(colour.get_red() >> 8), (uint8_t)(colour.get_green() >> 8), (uint8_t)(colour.get_blue() >> 8)));
		row = *(liststore_->insert(selected));
	}
	row[columns_.iter_] = iter;
	row[columns_.red_] = row.get_value(columns_.iter_)->r;
	row[columns_.green_] = row.get_value(columns_.iter_)->g;
	row[columns_.blue_] = row.get_value(columns_.iter_)->b;
	if (button_remove_->get_sensitive() == false) {
		button_remove_->set_sensitive(true);
	}
	display_->updateImage();
}

void GradientChooser::on_button_remove_clicked() {
	assert(colours_ != NULL);
	assert(display_ != NULL);
	Glib::RefPtr<Gtk::TreeSelection> selection = treeview_->get_selection();
	if (selection->count_selected_rows() == 0) {
		return;
	}
	colours_->erase((*(selection->get_selected()))[columns_.iter_]);
	liststore_->erase(selection->get_selected());
	if (liststore_->children().size() < 3) {
		button_remove_->set_sensitive(false);
	}
	display_->updateImage();
}
